/**
 * Created with CLion.
 * Description: 线扩充(线程安全)堆栈
 * User: loong
 * Date: 2020-09-09
 * Time: 22:36
 */

#include <exception>
#include <memory>
#include <mutex>
#include <stack>

struct empty_stack
    : std::exception
{
    const char *what() const throw()
    {
        return "empty stack!";
    }
};

template<typename T>
class thread_safe_stack
{
private:
    std::stack<T> data;
    
    mutable std::mutex m;

public:
    thread_safe_stack()
        : data(std::stack<T>())
    { }
    
    thread_safe_stack(const thread_safe_stack &other)
    {
        std::lock_guard<std::mutex> lock(other.m);
        data = other.data; // 1 在构造函数体中的执行拷贝
    }
    
    thread_safe_stack &operator=(const thread_safe_stack &) = delete;
    
    void push(T new_value)
    {
        std::lock_guard<std::mutex> lock(m);
        data.push(new_value);
    }
    
    std::shared_ptr<T> pop()
    {
        std::lock_guard<std::mutex> lock(m);
        if (data.empty()) throw empty_stack(); // 在调用pop前，检查栈是否为空
        std::shared_ptr<T> const res(std::make_shared<T>(data.top())); // 在修改堆栈前，分配出返回值
        data.pop();
        return res;
    }
    
    void pop(T &value)
    {
        std::lock_guard<std::mutex> lock(m);
        if (data.empty()) throw empty_stack();
        
        value = data.top();
        data.pop();
    }
    
    bool empty() const
    {
        std::lock_guard<std::mutex> lock(m);
        return data.empty();
    }
};